using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Catastrophe.Common.AttributeEx;

namespace Catastrophe.Common.Redis
{
	public class RedisCache
	{
		private readonly RedisUtil _redisUtil;

		public RedisCache(RedisUtil redisUtil)
		{
			this._redisUtil = redisUtil;
		}

		public Tuple<bool, string> CacheGet<T>(T t) where T : class, new()
		{
			PropertyInfo[] properties = t.GetType().GetProperties();
			List<CacheAbInfo> list = new List<CacheAbInfo>();
			PropertyInfo[] array = properties;
			foreach (PropertyInfo propertyInfo in array)
			{
				RedisCacheAttribute customAb = BuildAttribute.GetCustomAb<T, RedisCacheAttribute>(propertyInfo);
				if (customAb != null)
				{
					list.Add(new CacheAbInfo
					{
						RedisDescribe = customAb,
						Value = propertyInfo.GetValue(t),
						Property = propertyInfo
					});
				}
			}
			List<IGrouping<RedisDataTypeEnum, CacheAbInfo>> list2 = (from x in list
				group x by x.RedisDescribe.DataType).ToList();
			foreach (IGrouping<RedisDataTypeEnum, CacheAbInfo> item in list2)
			{
				switch (item.Key)
				{
				case RedisDataTypeEnum.Hash:
					this.HashGet(item.ToList(), t);
					break;
				case RedisDataTypeEnum.String:
					this.StringGet(item.ToList(), t);
					break;
				case RedisDataTypeEnum.List:
					this.ListGet(item.ToList(), t);
					break;
				}
			}
			return new Tuple<bool, string>(item1: false, "");
		}

		public Tuple<bool, string> CacheSet<T>(T t, string customKey = "") where T : class, new()
		{
			PropertyInfo[] properties = t.GetType().GetProperties();
			List<CacheAbInfo> list = new List<CacheAbInfo>();
			PropertyInfo[] array = properties;
			foreach (PropertyInfo propertyInfo in array)
			{
				RedisCacheAttribute customAb = BuildAttribute.GetCustomAb<T, RedisCacheAttribute>(propertyInfo);
				if (customAb != null)
				{
					CacheAbInfo cacheAbInfo = new CacheAbInfo
					{
						RedisDescribe = customAb,
						Value = propertyInfo.GetValue(t),
						Property = propertyInfo
					};
					if (!string.IsNullOrWhiteSpace(customKey))
					{
						cacheAbInfo.RedisDescribe.KeyName = customKey;
					}
					list.Add(cacheAbInfo);
				}
			}
			List<IGrouping<RedisDataTypeEnum, CacheAbInfo>> list2 = (from x in list
				group x by x.RedisDescribe.DataType).ToList();
			Tuple<bool, string> tuple = new Tuple<bool, string>(item1: true, "");
			Tuple<bool, string> tuple2 = new Tuple<bool, string>(item1: true, "");
			Tuple<bool, string> tuple3 = new Tuple<bool, string>(item1: true, "");
			foreach (IGrouping<RedisDataTypeEnum, CacheAbInfo> item in list2)
			{
				switch (item.Key)
				{
				case RedisDataTypeEnum.Hash:
					tuple = this.HashSet(item);
					break;
				case RedisDataTypeEnum.List:
					tuple3 = this.ListSet(item);
					break;
				case RedisDataTypeEnum.String:
					tuple2 = this.StringSet(item);
					break;
				default:
					throw new Exception("不支持的Redis数据类型！");
				}
			}
			StringBuilder stringBuilder = new StringBuilder();
			if (!tuple.Item1)
			{
				stringBuilder.Append(tuple.Item2 + Environment.NewLine);
			}
			if (!tuple2.Item1)
			{
				stringBuilder.Append(tuple2.Item2 + Environment.NewLine);
			}
			if (!tuple3.Item1)
			{
				stringBuilder.Append(tuple3.Item2 + Environment.NewLine);
			}
			return new Tuple<bool, string>(tuple.Item1 && tuple2.Item1, stringBuilder.ToString());
		}

		private Tuple<bool, string> HashSet(IGrouping<RedisDataTypeEnum, CacheAbInfo> ds)
		{
			if (ds == null)
			{
				throw new ArgumentNullException("ds");
			}
			if (!ds.Any())
			{
				return new Tuple<bool, string>(item1: false, "数据源长度0");
			}
			try
			{
				IEnumerable<IGrouping<string, CacheAbInfo>> enumerable = from x in ds
					group x by x.RedisDescribe.KeyName;
				foreach (IGrouping<string, CacheAbInfo> item in enumerable)
				{
					Dictionary<string, object> dictionary = new Dictionary<string, object>();
					foreach (CacheAbInfo item2 in item)
					{
						string text = (string.IsNullOrWhiteSpace(item2.RedisDescribe.FiledName) ? item2.Property.Name : item2.RedisDescribe.FiledName);
						dictionary.Add(text, item2.Value?.ToString());
					}
					this._redisUtil.HashPutAll(item.Key, dictionary);
				}
				return new Tuple<bool, string>(item1: true, "");
			}
			catch (Exception ex)
			{
				return new Tuple<bool, string>(item1: false, ex.ToString());
			}
		}

		private Tuple<bool, string> HashGet<T>(List<CacheAbInfo> keyList, T t)
		{
			if (keyList == null)
			{
				throw new ArgumentNullException("keyList");
			}
			if (t == null)
			{
				throw new ArgumentNullException("t");
			}
			if (keyList.Count == 0)
			{
				return new Tuple<bool, string>(item1: false, "数据源长度0");
			}
			try
			{
				PropertyInfo[] properties = typeof(T).GetProperties();
				List<IGrouping<string, CacheAbInfo>> list = (from x in keyList
					group x by x.RedisDescribe.KeyName).ToList();
				foreach (IGrouping<string, CacheAbInfo> item in list)
				{
					if (string.IsNullOrWhiteSpace(item.Key))
					{
						continue;
					}
					Dictionary<object, object> dictionary = this._redisUtil.HashGetAll(item.Key);
					foreach (dynamic field in dictionary.Keys)
					{
						PropertyInfo propertyInfo = properties.FirstOrDefault((PropertyInfo x) => x.Name == field);
						if (propertyInfo != null)
						{
							DataConverter.PropertySetValue(t, propertyInfo, dictionary[field].ToString());
						}
					}
				}
				return new Tuple<bool, string>(item1: true, "");
			}
			catch (Exception ex)
			{
				return new Tuple<bool, string>(item1: false, ex.ToString());
			}
		}

		private Tuple<bool, string> StringSet(IGrouping<RedisDataTypeEnum, CacheAbInfo> ds)
		{
			if (ds == null)
			{
				throw new ArgumentNullException("ds");
			}
			if (!ds.Any())
			{
				return new Tuple<bool, string>(item1: false, "数据源长度0");
			}
			try
			{
				foreach (CacheAbInfo d in ds)
				{
					TimeSpan? timeSpan = ((d.RedisDescribe.ExpiryMillionSeconds > 0) ? new TimeSpan?(TimeSpan.FromMilliseconds(d.RedisDescribe.ExpiryMillionSeconds)) : null);
					this._redisUtil.StringSet(d.Property.Name, d.Value, timeSpan);
				}
				return new Tuple<bool, string>(item1: true, "");
			}
			catch (Exception ex)
			{
				return new Tuple<bool, string>(item1: false, ex.ToString());
			}
		}

		private Tuple<bool, string> StringGet<T>(List<CacheAbInfo> keyList, T t)
		{
			if (keyList == null)
			{
				throw new ArgumentNullException("keyList");
			}
			if (!keyList.Any())
			{
				return new Tuple<bool, string>(item1: false, "数据源长度0");
			}
			try
			{
				PropertyInfo[] properties = typeof(T).GetProperties();
				foreach (CacheAbInfo value in keyList)
				{
					if (!string.IsNullOrWhiteSpace(value.Property.Name))
					{
						string value2 = this._redisUtil.StringGet(value.Property.Name);
						PropertyInfo propertyInfo = properties.FirstOrDefault((PropertyInfo x) => x.Name == value.Property.Name);
						if (propertyInfo != null)
						{
							DataConverter.PropertySetValue(t, propertyInfo, value2);
						}
					}
				}
				return new Tuple<bool, string>(item1: true, "");
			}
			catch (Exception ex)
			{
				return new Tuple<bool, string>(item1: false, ex.ToString());
			}
		}

		private Tuple<bool, string> ListSet(IGrouping<RedisDataTypeEnum, CacheAbInfo> ds)
		{
			if (ds == null)
			{
				throw new ArgumentNullException("ds");
			}
			if (!ds.Any())
			{
				return new Tuple<bool, string>(item1: false, "数据源长度0");
			}
			try
			{
				IEnumerable<IGrouping<string, CacheAbInfo>> enumerable = from x in ds
					group x by x.RedisDescribe.KeyName;
				foreach (IGrouping<string, CacheAbInfo> item in enumerable)
				{
					foreach (CacheAbInfo item2 in item)
					{
						if (item2 != null)
						{
							this._redisUtil.ListSet(item.Key, item2.RedisDescribe.Index, item2.Value);
						}
					}
				}
				return new Tuple<bool, string>(item1: true, "");
			}
			catch (Exception ex)
			{
				return new Tuple<bool, string>(item1: false, ex.ToString());
			}
		}

		private Tuple<bool, string> ListGet<T>(List<CacheAbInfo> keyList, T t)
		{
			if (keyList == null)
			{
				throw new ArgumentNullException("keyList");
			}
			if (t == null)
			{
				throw new ArgumentNullException("t");
			}
			if (keyList.Count == 0)
			{
				return new Tuple<bool, string>(item1: false, "数据源长度0");
			}
			try
			{
				PropertyInfo[] properties = typeof(T).GetProperties();
				List<IGrouping<string, CacheAbInfo>> list = (from x in keyList
					group x by x.RedisDescribe.KeyName).ToList();
				foreach (IGrouping<string, CacheAbInfo> item in list)
				{
					if (string.IsNullOrWhiteSpace(item.Key))
					{
						continue;
					}
					foreach (CacheAbInfo each in item)
					{
						string value = this._redisUtil.ListGet(item.Key, each.RedisDescribe.Index);
						PropertyInfo propertyInfo = properties.FirstOrDefault((PropertyInfo x) => x.Name == each.Property.Name);
						if (propertyInfo != null)
						{
							DataConverter.PropertySetValue(t, propertyInfo, value);
						}
					}
				}
				return new Tuple<bool, string>(item1: true, "");
			}
			catch (Exception ex)
			{
				return new Tuple<bool, string>(item1: false, ex.ToString());
			}
		}
	}
}
